/*
 * @Author: “ygnnli” “1585923072@qq.com”
 * @Date: 2024-08-04 10:32:03
 * @LastEditors: “ygnnli” “1585923072@qq.com”
 * @LastEditTime: 2024-08-05 18:00:34
 * @FilePath: /110/51/tcp_echo_server/TcpServer.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include "InetAddr.hpp"
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <functional>
#include <memory>
#include "Socket.hpp"

using namespace socket_ns;
class TcpServer; // 前向声明

using http_t = std::function<std::string(std::string reqeust)>;

class ThreadData
{
public:
    ThreadData(socket_sptr fd, InetAddr addr, TcpServer *s) : sockfd(fd), clientaddr(addr), self(s)
    {
    }

public:
    socket_sptr sockfd;
    InetAddr clientaddr;
    TcpServer *self; // 获取TcpServer对象指针
};

class TcpServer
{
public:
    TcpServer(int port, http_t service) : _http_service(service), _localaddr("0", port), _listensock(std::make_unique<TcpSocket>()), _isrunning(false)
    {
        _listensock->BuildListenSocket(_localaddr); // 直接完成初始化 构建套接字+绑定+监听
    }
    ~TcpServer()
    {
    }

    static void *HandlerSock(void *args) // 线程处理函数
    {
        pthread_detach(pthread_self()); // 设置线程分离
        ThreadData *td = static_cast<ThreadData *>(args);
        std::string request, response;
        // 有较大的概率，读到的就是一个完整的http request  我们这里不做处理--- 节省时间
        ssize_t n = td->sockfd->Recv(&request); // 读取请求
        if (n > 0)
        {
            response = td->self->_http_service(request); // 调用TcpServer的Service函数
            td->sockfd->Send(response);                  // 发送应答
        }

        td->sockfd->Close(); // 关闭套接字 否则文件描述符泄漏
        delete td;
        return nullptr;
    }
    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            InetAddr peeraddr;                                         // 客户端地址
            socket_sptr normalsock = _listensock->Accepter(&peeraddr); // 接受客户端连接
            if (normalsock == nullptr)
                continue;
            // Version 2 采用多线程
            pthread_t t;
            ThreadData *td = new ThreadData(normalsock, peeraddr, this); // 创建线程数据
            pthread_create(&t, nullptr, HandlerSock, td);                // 创建线程
        }
        _isrunning = false;
    }

private:
    InetAddr _localaddr; // 服务器端口
    std::unique_ptr<Socket> _listensock;
    bool _isrunning; // 服务器是否在运行

    http_t _http_service;
};